package fons.navigator.load.reader;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import au.com.bytecode.opencsv.CSVReader;

import com.google.common.collect.Sets;

import fons.model.ontology.Context;
import fons.model.ontology.Dimension;
import fons.model.ontology.Value;
import fons.navigator.util.IOUtils;

public class CsvValueReader implements ValueReader {

	private final Context context;
	private final String filename;
	private final String encoding;
	private final char separator;
	private final Map<String, String> synonymes;

	public CsvValueReader(Context context, String filename, String encoding,
			String separator, Map<String, String> synonymes) {
		this.context = context;
		this.filename = filename;
		this.encoding = encoding;
		this.separator = separator.charAt(0);
		this.synonymes = synonymes;
	}

	private List<Dimension> dimensionByColumns = new Vector<Dimension>();

	@Override
	public Collection<Value> readValues() throws IOException {
		CSVReader csv = null;
		List<Value> values = new Vector<Value>();

		try {
			csv = new CSVReader(new InputStreamReader(IOUtils.asInputStream(filename), encoding), separator);

			String[] csvLine;
			int line = 1;
			while ((csvLine = csv.readNext()) != null) {
				if (line == 1) {
					for (String csvColumnHeader: csvLine) {
						if (!csvColumnHeader.startsWith("h:")) {
							if (!csvColumnHeader.matches("^\\s*$")) {
								if (synonymes.containsKey(csvColumnHeader)) {							
									dimensionByColumns.add(context.getDimension(synonymes.get(csvColumnHeader)));
								} else {
									dimensionByColumns.add(context.getDimension(csvColumnHeader));
								}
							} else {
								dimensionByColumns.add(null);
							}
						} else {
							dimensionByColumns.add(null);
						}
					}

				} else {
					int column = 0;
					Set<Dimension> dimensions = Sets.newHashSet();

					for (String csvColumn: csvLine) {
						if (dimensionByColumns.get(column) != null) {
							dimensions.add(dimensionByColumns.get(column));
						}

						try { 
							final Value value = context.create(Double.parseDouble(csvColumn));
							for (Dimension dimension: dimensions) {
								value.as(dimension);
							}
							values.add(value);

						} catch (NumberFormatException ex) {
							String dimension = csvColumn;

							if (dimension.startsWith(":")) {
								dimension = dimension.substring(1);
							}

							if (synonymes.containsKey(dimension)) {
								dimension = synonymes.get(dimension);
							}

							dimensions.add(context.getDimension(dimension));
						}

						dimensions.remove(dimensionByColumns.get(column));					
						column++;
					}					
				}

				line++;
			}

		} catch (Exception ioe) {
			throw new IOException(
					"Error reading from location '" + filename + "': " + ioe.getMessage(), ioe);

		} finally {
			if (csv != null) {
				csv.close();
			}
		}

		return values;
	}


	public static CsvValueReader create(Context context, String filename,
			String encoding, String separator, Map<String, String> synonymes) {
		return new CsvValueReader(context, filename, encoding, separator, synonymes);
	}

}
